#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<stropts.h>
#include<linux/fb.h>
#include <sys/mman.h>
#include<math.h>
#include<linux/input.h>
#include<dirent.h>
#include<pwd.h>
#include<grp.h>
// #include<time.h>
#include"sxlb.h"

#define LCD "/dev/ubuntu_lcd"
#define EVENT "/dev/ubuntu_event"
#define SIZE_LCD (800*480*4)

typedef unsigned int* lcd;
typedef unsigned int uint;
typedef unsigned char uch;


lcd open_lcd(int* lcdfd){
    *lcdfd = open(LCD,O_RDWR);
    if(-1 == *lcdfd){
        perror("open err");
        return NULL;
    }
    // printf("设备打开成功\n");


    lcd p=mmap(NULL,SIZE_LCD,PROT_READ | PROT_WRITE,MAP_SHARED,*lcdfd,0);
    if(MAP_FAILED == p){
        // perror("映射内存失败");
        return NULL;
    }

    // printf("映射成功\n");
    return p;
}

int close_lcd(lcd p,int *lcdfd){

    int ret = munmap(p,SIZE_LCD);
    if(-1 == ret){
        // perror("解除映射失败");
    }
    // printf("解除映射成功\n");
    ret = close(*lcdfd);
    if(-1 == ret){
        // perror("关闭设备失败\n");
        return -1;
    }
    // printf("设备已关闭\n");
    return 0;

}

unsigned int Rgb(uint r,uint g,uint b){//通过设置rgb三种数值调色

    uint rgb=(r<<16)|(g<<8)|b;

    return rgb;
}

void backgroud(uint rgb){    //输入颜色数值打印纯色背景
    int lcdfd =-1;
    lcd p=open_lcd(&lcdfd);

    //粉色:255,192,203//
    for(int i =0;i < SIZE_LCD/4;i++){
        p[i]=rgb;
    }

    close_lcd(p,&lcdfd);


}

void print(int x,int y,const char* picture){ //将图片从坐标(x,y)开始打印
    int bmpfd = open(picture,O_RDONLY);
    if(bmpfd == -1){
        perror("open err");
        return;
    }
    int lcdfd=-1;
    lcd p=open_lcd(&lcdfd);

    uch info[54]={0};
    read(bmpfd,info,54);

    // printf("文件标识:%c%c\n",info[0],info[1]);

    uint fSIZE_LCD = (info[5]<< 24) | (info[4]<<16) | (info[3]<<8) | (info[2]<<0);
    // printf("文件总大小:%d\n",fSIZE_LCD);

    uint bmp_w=(info[21]<< 24) | (info[20]<<16) | (info[19]<<8) | (info[18]<<0);
    uint bmp_h=(info[25]<< 24) | (info[24]<<16) | (info[23]<<8) | (info[22]<<0);
    // printf("宽:%d 高:%d \n",bmp_w,bmp_h);


    uch* bmpbuf = (uch*)malloc(bmp_h*bmp_w*3);
    if(bmpbuf == NULL){
        printf("bmpbuf err\n");
        return ;
    }
    read(bmpfd,bmpbuf,bmp_h*bmp_w*3);

    uint* lcdbuf =(uint*)malloc(bmp_h*bmp_w*sizeof(uint));
    if(lcdbuf == NULL){
        printf("lcdbuf err\n");
        return ;
    }


    for(int i =0;i<bmp_h*bmp_w;i++){
        lcdbuf[i] = (bmpbuf[i*3+0]<<0) | (bmpbuf[i*3+1]<<8) | (bmpbuf[i*3+2]<<16);
    }
    for(int i=y;i< bmp_h+y;i++){
        for(int j=x;j<bmp_w+x;j++){
            if( (j+i*800) > (800*480)){
                return;
            }
            if( (j+i*800) < 0){
                return;
            }

            p[j+i*800]=lcdbuf[(j-x)+(bmp_h-(i-y)-1)*bmp_w];
        }
    }

    close_lcd(p,&lcdfd);
    free(bmpbuf);
    free(lcdbuf);
    bmpbuf=NULL;
    lcdbuf=NULL;


    int ret=close(bmpfd);
    if(-1 == ret){
        printf("err\n");
        return ;
    }
}

void get_xy(int* x,int* y){//获取点击的xy值

    //打开设备
    int tsfd =open(EVENT,O_RDONLY);
    if(-1 == tsfd){
        perror("open err");
        return;
    }

    struct input_event ts;

    while(1){
        //获取设备事件信息
        int ret =read(tsfd,&ts,sizeof(ts));
        if(-1 == ret){
            perror("read err");
            break;
        }
        if(ts.type == EV_ABS && ts.code == ABS_X){
            *x=ts.value;
        }else if(ts.type == EV_ABS && ts.code == ABS_Y){
            *y = ts.value;
            if(*x >= 0){
                break;
            }

        }


    }

    close(tsfd);

}

link_node_t* search(double_list_t p, int post){//定位链表位置
    if(p == NULL){
        printf("头尾指针内存分配错误!\n");
        return NULL;
    }
    if(p->len <= post || post < 0){
        printf("插入位置不合法!\n");
        return NULL;
    }
    if(post == p->len-1){
       link_node_t* temp=p->tail;
       return temp;
    }
    else{
        link_node_t* temp=p->head->next;
        for(int i =0;i<post;i++){
            temp=temp->next;
        }
        return temp;
    }
}

void found(char* ch,FILE*fp,char fu){//使文件流fp指到':'下一个位置

    while((*ch) != fu){
        if((*ch) == -1){
            return;
        }
        (*ch)=fgetc(fp);
    }
    (*ch)=fgetc(fp);
    return;
}

order_list_t order_get(char* ch,FILE*fp){//将menu.txt的数据转换,并存入结构体
    
    
    order_list_t ordernode=(order_list_t)malloc(sizeof(order_node_t));
    int n=0;
    char temp[64]={0};
    found(ch,fp,':');
    while ((*ch) != ' ')
    {   
        if((*ch) == -1){
            free(ordernode);
            ordernode=NULL;
            return NULL;
        }
        temp[n]=(*ch);
        n++;
        (*ch)=fgetc(fp);
    }
    temp[n]=0;
    ordernode->value=atof(temp);
    found(ch,fp,':');

    n=0;

    while ((*ch) != ' ')
    {   
        
        ordernode->name[n]=(*ch);
        (*ch)=fgetc(fp);
        n++;
    }
    ordernode->name[n]=0;
    n=0;

    found(ch,fp,':');
    found(ch,fp,':');
    while ((*ch) != ',')
    {   
        
        temp[n]=(*ch);
        (*ch)=fgetc(fp);
        n++;
    }
    temp[n]=0;
    ordernode->number=atof(temp);
    // printf("%s,%d,%d\n",ordernode->name,ordernode->value,ordernode->number);
    return ordernode;
}

double_list_t picopen(){//获取menu.txt里的数据，存入结构体，将结构体的地址存入链表

    double_list_t list = createEmptyDoubleLinkList();
    if (list == NULL) {
        printf("创建双向链表失败!\n");
        return NULL;
    }
    FILE*fp = fopen("./menu.txt","r");
    if(fp == NULL){
        printf("fopen err\n");
        return NULL;
    }
    int n=0;
    char ch=0;
    order_list_t node=NULL;
    while(ch != -1){
            node=order_get(&ch,fp);
            if(node != NULL){
                insertIntoDoubleLinkList(list, n,node);
            }else{
                return list;
            }
            
    }
    
    return list;

}

void clear_number(const double_list_t p,int* total){//将金额和各个菜品数量清零
    if(p == NULL){
        printf("头尾指针内存分配错误!\n");
        return ;
    }
    if(isEmptyDoubleLinkList(p) == 0){
        printf("链表为空");
        return;
    }
    link_node_t* temp=p->head->next;
    *total=0;
    int i=0;
    while(temp != NULL){
        temp->data->number=0;
        temp=temp->next;
        i++;
    }
    return;
    
}
    
void clearpicopen(const double_list_t p){//将储存文件相对路径的堆释放
    if(p == NULL){
        printf("头尾指针内存分配错误!\n");
        return ;
    }
    if(isEmptyDoubleLinkList(p) == 0){
        printf("链表为空");
        return;
    }
    link_node_t* temp=p->head->next;
    int i=0;
    while(temp != NULL){
        free(temp->data);
        temp->data=NULL;
        temp=temp->next;
    }
    printf("picopen clear success\n");
    return;
}

void page_number(int page){//传入页面数据,打印页面数字
    if(page !=0 ){
        page=(page/3)+1;
    }else{
        page=1;
    }
    
    switch (page)
    {
    case 1:
        print(747,359,"./n1.bmp");
        break;
    case 2:
        print(747,359,"./n2.bmp");
        break;
    case 3:
        print(747,359,"./n3.bmp");
        break;
    default:
        break;
    }
    return;
}

int number_digits(int fvalue,int i,int level){//将整数的数位分离出来
    int n=0;
    if(level == i){
        n=fvalue / pow(10,(i-1));
    }else if((i-1) == 0){
        n=fvalue %10;
    }else{
        n=(fvalue % (int)pow(10,i) )/ (int)pow(10,(i-1));
    }
    return n;
    

}

void number_value_print(int number,int x,int y){//根据number的值,打印相应的图片
    
    switch (number)
    {
    case 0:
        print(x,y,"./total/0.bmp");
        break;
    case 1:
        print(x,y,"./total/1.bmp");
        break;
    case 2:
        print(x,y,"./total/2.bmp");
        break;
    case 3:
        print(x,y,"./total/3.bmp");
        break;
    case 4:
        print(x,y,"./total/4.bmp");
        break;
    case 5:
        print(x,y,"./total/5.bmp");
        break;
    case 6:
        print(x,y,"./total/6.bmp");
        break;
    case 7:
        print(x,y,"./total/7.bmp");
        break;
    case 8:
        print(x,y,"./total/8.bmp");
        break;
    case 9:
        print(x,y,"./total/9.bmp");
        break;
    default:
        break;
    }
    return;
}

void print_value(int value,int x,int y){//打印总价格

    int level=1,n=0,fvalue=value;
    if(value != 0){
        while( fvalue ){
            fvalue=fvalue/10;
            if(fvalue !=0){
                level++;
            }
        }
        
    }
    for(int i=level;i > 0;i--){
        n=number_digits(value,i,level);
        number_value_print(n,x,y);
        x+=20;
        // printf("%d\n",n);
    }
    return;
}

int value_total(const double_list_t p){//结算总价格
    if(p == NULL){
        printf("头尾指针内存分配错误!\n");
        return -1;
    }
    if(isEmptyDoubleLinkList(p) == 0){
        printf("链表为空");
        return -1;
    }
    link_node_t* temp=p->head->next;
    int total=0;
    while(temp != NULL){
        total+=temp->data->number*temp->data->value;
        // printf("%s,%d,%d\n",temp->data->name,temp->data->value,temp->data->number);
        temp=temp->next;

    }
    return total;
}

void pay(int* x,int* y){//进入支付页面

    while(1){
        print(0,0,"./weixin.bmp");
        print(0,419,"./back.bmp");
        get_xy(x,y);
        if((*x) > 0 && (*x) < 100 && (*y) > 419 && (*y) < 479){//退出
            return;
        }
        *x=-1;
        *y=-1;
    }

    return;
}

void page_print(int total,int page,link_list_t node1,link_list_t node2,link_list_t node3,double_list_t list){//打印选购页面图片
    print(0,0,"./w.bmp");
    print(100,0,node1->data->name);
    print(300,0,node2->data->name);
    print(500,0,node3->data->name);
    print(100,200,"./number.bmp");
    print(300,200,"./number.bmp");
    print(500,200,"./number.bmp");
    print(679,419,"./move.bmp");
    print(679,359,"./shop.bmp");
    print(0,419,"./back.bmp");
    print(679,304,"./clear.bmp");
    print_value(node1->data->number,180,200);
    print_value(node2->data->number,380,200);
    print_value(node3->data->number,580,200);
    print_value(total,100,407);
    page_number(page);
    return;
}

int keybordclick(int* x,int* y,int* page){//通过page的值来实现翻页功能,点击改变page的值

    if(((*x) > 679 && (*x) < 739 && (*y) > 419 && (*y) < 479)){//向前翻页
        (*page)--;
        if(*page <= 0){
            *page=3;
        }
        return 1;
    }
    if((*x) > 739 && (*x) < 799 && (*y) > 419 && (*y) < 479){//向后翻页
        (*page)++;
        if(*page > 3){
            *page=1;
        }
        return 1;
    }

    return -1;
}

int keyfeedback(int* total,int*x,int* y,int* page,link_list_t node1,link_list_t node2,link_list_t node3,double_list_t list){//选购页面各种按钮的反馈
    if((*x) > 679 && (*x) < 739 && (*y) > 304 && (*y) < 359){//退出
        clear_number(list,total);
    }
    if((*x) > 0 && (*x) < 100 && (*y) > 419 && (*y) < 479){//退出
        return 1;
    }
    if((*x) > 679 && (*x) < 739 && (*y) > 359 && (*y) < 419){//购买
        pay(x,y);
    }
    if((*x) > 100 && (*x) < 200 && (*y) > 200 && (*y) < 252){//菜品1添加
        node1->data->number++;
        *total+=node1->data->value;
        print(276,256,"./add.bmp");
        sleep(1);
    }
    if((*x) > 200 && (*x) < 300 && (*y) > 200 && (*y) < 252){//菜品1减少
        node1->data->number--;
        if(node1->data->number<0){
            node1->data->number=0;
        }else{
            *total-=node1->data->value;
        }
    }
    if((*x) > 300 && (*x) < 400 && (*y) > 200 && (*y) < 252){//菜品2添加
        node2->data->number++;
        *total+=node2->data->value;
        print(276,256,"./add.bmp");
        sleep(1);
    }
    if((*x) > 400 && (*x) < 500 && (*y) > 200 && (*y) < 252){//菜品2减少
        node2->data->number--;
        if(node2->data->number<0){
            node2->data->number=0;
        }else{
            *total-=node2->data->value;
        }
    }
    if((*x) > 500 && (*x) < 600 && (*y) > 200 && (*y) < 252){//菜品3添加
        node3->data->number++;
        *total+=node3->data->value;
        print(276,256,"./add.bmp");
        sleep(1);
    }
    if((*x) > 600 && (*x) < 700 && (*y) > 200 && (*y) < 252){//菜品3减少
        node3->data->number--;
        if(node3->data->number<0){
            node3->data->number=0;
        }else{
            *total-=node3->data->value;
        }
    }
    if((*x) > 679 && (*x) < 739 && (*y) > 419 && (*y) < 479){
        *page-=3;
        if(*page < 0){
            *page=6;
        }
    }
    if((*x) > 739 && (*x) < 799 && (*y) > 419 && (*y) < 479){
        *page+=3;
        if(*page > 7){
            *page=0;
        }
    }
    return 0;
}

void orderview(int* x,int* y,double_list_t list){//选购页面

    int page=0,true=0,total=0;
    link_list_t node1=NULL;
    link_list_t node2=NULL;
    link_list_t node3=NULL;
    clear_number(list,&total);
    while(1){
        node1=search(list,page);
        node2=node1->next;
        node3=node2->next;
        page_print(total,page,node1,node2,node3,list);
        
        get_xy(x,y);
        true=keyfeedback(&total,x,y,&page,node1,node2,node3,list);
        if(true == 1){
            return;
        }

        *x=-1;
        *y=-1;
    }

    return;
}

void blackpoint(int times){//输入密码的黑点打印
    uint position=65;
    
    for(int i = 0;i < times;i++){
        if(position > 310){
            break;
        }
        print(position,215,"./point.bmp");
        
        position+=60;
    }

    return;
}

char keybord(int* x,int* y){//密码登陆界面的按键反馈

    //一
        if((*x) > 452 && (*x) < 536 && (*y) > 80 && (*y) < 145){
            return '1';
            
        }
        if((*x) > 556 && (*x) < 642 && (*y) > 80 && (*y) < 145){
            return '2';
            
        }
        if((*x) > 663 && (*x) < 745 && (*y) > 80 && (*y) < 145){
            return '3';
            
        }
    //二
        if((*x) > 452 && (*x) < 536 && (*y) > 162 && (*y) < 227){
            return '4';
            
        }
        if((*x) > 556 && (*x) < 642 && (*y) > 162 && (*y) < 227){
            return '5';
            
        }
        if((*x) > 663 && (*x) < 745 && (*y) > 162 && (*y) < 227){
            return '6';
            
        }
    //三
        if((*x) > 452 && (*x) < 536 && (*y) > 243 && (*y) < 310){
            return '7';
            
        }
        if((*x) > 556 && (*x) < 642 && (*y) > 243 && (*y) < 310){
            return '8';
            
        }
        if((*x) > 663 && (*x) < 745 && (*y) > 243 && (*y) < 310){
            return '9';
            
        }
    //四
        if((*x) > 452 && (*x) < 536 && (*y) > 323 && (*y) < 390){
            return 1;
            
        }
        if((*x) > 556 && (*x) < 642 && (*y) > 323 && (*y) < 390){
            return '0';
            
        }
        if((*x) > 663 && (*x) < 745 && (*y) > 323 && (*y) < 390){
            return 0;
        }

    return -1;
}

void load(int sec){//进度条加载界面 sec代表加载秒数
    print(0,0,"./w.bmp");
    print(299,189,"./welcome.bmp");
    sleep(1);
    uint position=0;
    if(20 % sec != 0){
        for(int i = 0;i< (20%sec) ;i++){
            print(position,340,"./s.bmp");
            position+=40;
        }
        sleep(1);
        sec--;
    }
    for(int i = 0;i<sec;i++){
        for(int i = 0;i<20/sec;i++){
            print(position,340,"./s.bmp");
            position+=40;
        }
        sleep(1);
    }
    
    return;
}

void loginalbum(int* x,int* y){//密码登陆界面
    double_list_t list=picopen();
    int times=0,wrong=0,len=0;
    uint position=65;
    char ch=-1;
    char password[]="12";
    char printpass[64]={0};
    len=sizeof(printpass);
    memset(printpass,0,len);
    while(1){
        
        print(0,0,"./login.bmp");
        print(0,419,"./back.bmp");
        blackpoint(times);
        get_xy(x,y);
        if((*x) > 0 && (*x) < 100 && (*y) > 419 && (*y) < 479){//退出 
            clearpicopen(list);//释放链表的数据
            clearsxlb(list);//释放链表
            return;
        }
        ch=keybord(x,y);
        if( '0' <= ch && ch <= '9'){//键盘数字输入
            times++;
            if(0 < times && times <= (len-1) ){
                printpass[(times-1)]=ch;
                
            }
        }
        if(ch == 1){//删除
            if(0 < times && times <= (len-1) ){
                printpass[(times-1)]=0;
                times--;
            }
        }
        if(ch == 0){
            if(strcmp(password,printpass) == 0){
                // load();
                // album(x,y);
                orderview(x,y,list);
                // show(list);
                // print_value(5,0,407);
            }else{
                wrong++;
                times=0;
                memset(printpass,0,len);
            }
        }
        //
        if(wrong >= 3){
            clearpicopen(list);//释放链表的数据
            clearsxlb(list);//释放链表
            return;
        }
        
        *x=-1;
        *y=-1;
    }
    clearpicopen(list);//释放链表的数据
    clearsxlb(list);//释放链表
    return;
}

void order_welcome(int* x,int* y){//首页
    print(0,0,"./background.bmp");
    sleep(1);
    print(299,189,"./welcome.bmp");
    sleep(1);
    load(3);
    loginalbum(x,y);
    backgroud(0);
    return;
}